# -------------------------------------------------
#    请不要随意修改文件中的代码
# -------------------------------------------------

import threading
import socket
import json
import php2python

REQUEST_MIN_LEN = 10    #合法的request消息包最小长度    
TIMEOUT = 180           #socket处理时间180秒

pc_dict = {}        #预编译字典，key:调用模块、函数、参数字符串，值是编译对象
global_env = {}     #global环境变量


class ProcessThread(threading.Thread):
    """
    ProcessThread 处理线程
    """
    def __init__(self, socket):
        threading.Thread.__init__(self)

        #客户socket
        self._socket = socket

    def run(self):

        #---------------------------------------------------
        #    1.接收消息
        #---------------------------------------------------
        
        try:  
            self._socket.settimeout(TIMEOUT)                  #设置socket超时时间
            firstbuf = self._socket.recv(16 * 1024).decode('utf-8')         #接收第一个消息包(bytes)
            if len(firstbuf) < REQUEST_MIN_LEN:               #不够消息最小长度
                print('error message,less than minimum length:',firstbuf)
                self._socket.close()
                return
            print(len(firstbuf))
            firstComma = firstbuf.index(',')
            totalLen = int(firstbuf[0:firstComma])            #消息包总长度
            print('message length:',totalLen)
            reqMsg = firstbuf[firstComma+1:]
            while (len(reqMsg) < totalLen):    
                reqMsg = reqMsg + self._socket.recv(16 * 1024).decode('utf-8')
            print ('reqMsg:',reqMsg)
        except Exception as e:  
            print('getMessage error',str(e))
            self.jsonReturn(0, ('getMessage error',str(e)))  #异常信息返回
            self._socket.close()
            exit()
            return

        #---------------------------------------------------
        #    2.调用模块、函数检查，预编译。
        #---------------------------------------------------

        #从消息包中解析出模块名、函数名、入参list

        reqMsg = json.loads(reqMsg)
        modul = reqMsg['m']
        func = reqMsg['a']
        params = reqMsg['p']
        print('module:',modul,'func:',func,'parmas:',params)

        if (modul not in pc_dict):   #预编译字典中没有此编译模块
            #检查模块、函数是否存在
            try:
                callMod = __import__ (modul)    #根据module名，反射出module
                pc_dict[modul] = callMod        #预编译字典缓存此模块
            except Exception as e:
                print ('module not exist:',modul)
                self.jsonReturn(0, "module '%s()' is not exist!" % func)  #异常信息返回
                self._socket.close()
                return
        else:
            callMod = pc_dict[modul]            #从预编译字典中获得模块对象
        try:
            callMethod = getattr(callMod, func)
        except Exception as e:
            print ('function not exist:',func)
            self.jsonReturn(0, "function '%s()' is not exist!" % func)  #异常信息返回
            self._socket.close()
            return

        #---------------------------------------------------
        #    3.Python函数调用
        #---------------------------------------------------

        try: 
            params = ','.join([repr(x) for x in params])         
            print ("call: %s(%s)" % (modul+'.'+func, params) )
            
            #加载函数
            compStr = "import %s\nret=%s(%s)" % (modul, modul+'.'+func, params)
            rpFunc = compile(compStr, "", "exec")
            
            if func not in global_env: 
                global_env[func] = rpFunc   
            local_env = {}
            exec (rpFunc, global_env, local_env)     #函数调用
        except Exception as e:  
            print ('call python error:',str(e))
            self.jsonReturn(0, str(e))  #异常信息返回
            self._socket.close()
            return

        #---------------------------------------------------
        #    4.结果返回给PHP
        #---------------------------------------------------
        self.jsonReturn(1, local_env['ret'])
        self._socket.close()
        return
    #
    def jsonReturn(self, status, message):
        print('send message:',json.dumps({'s':status,'m':message}))
        self._socket.sendall(json.dumps({'s':status,'m':message}).encode(php2python.CHARSET))